package geom;
import geom.Geom;
import geom.Vector;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;


public class Segment{
		private Line parent;
		int start;
		int end;
		float fit = Line.DEFAULT_FIT;
		float maxLength = Line.MAX_LENGTH;
		boolean visible;
		HashMap<Segment, Float> intersects;
		
		
		public Segment(Line parent, int start, int end){
			this.setParent(parent);
			this.start = start;
			this.end = end;
			visible = true;
		}
		public Segment(Line parent, int start, int end, boolean visible){
			this(parent, start, end);
			this.visible = visible;
			
		}
		
		public void extend(int i){
			end = end + i;
		}
		
		public void trim(int i){
			end = i;
		}
		
		public int fits(float fit){
			int worstFit = -1;
			float maxDev = 0f;
			for(int i = start+1; i < end; i++){
				float dev = Geom.getDistanceFromPointToLineXY(startPos(), endPos(), getParent().getPoints().get(i));
				if(dev > fit && dev > maxDev){
					worstFit = i;
					maxDev = dev;
				}
			}
			if(worstFit == -1){
				if(length() > maxLength)
					worstFit = end - 1;
			}
			return worstFit;
		}
		public float length(){
			return endPos().sub(startPos()).absLength();
		}
		
		public Vector startPos(){
			return getParent().getPoints().get(start);
		}
		public Vector endPos(){
			return getParent().getPoints().get(end);
		}
		
		public Vector getPosAt(float i){
			return startPos().add(relative().mult(i / length()));
		}
		
		public void draw(){
			if(!visible) return;
			getParent().pa.line(startPos().x, startPos().y, endPos().x, endPos().y);
			getParent().pa.ellipse(startPos().x, startPos().y, 2, 2);
			getParent().pa.ellipse(endPos().x, endPos().y, 2, 2);
		}
		
		public Vector relative(){
			return endPos().sub(startPos());
		}

		public void setParent(Line parent) {
			this.parent = parent;
		}

		public Line getParent() {
			return parent;
		}
		public Boolean intersects(Vector v1, Vector v2){
			return Geom.linesIntersectXY(startPos(), endPos(), v1, v2);
		}
		public Vector intersectsAt(Vector v1, Vector v2){
			return Geom.linesIntersectAtXY(startPos(), endPos(), v1, v2);
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + end;
			result = prime * result + Float.floatToIntBits(fit);
			result = prime * result + Float.floatToIntBits(maxLength);
			result = prime * result
					+ ((parent == null) ? 0 : parent.hashCode());
			result = prime * result + start;
			result = prime * result + (visible ? 1231 : 1237);
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			final Segment other = (Segment) obj;
			if (end != other.end)
				return false;
			if (Float.floatToIntBits(fit) != Float.floatToIntBits(other.fit))
				return false;
			if (Float.floatToIntBits(maxLength) != Float
					.floatToIntBits(other.maxLength))
				return false;
			if (parent == null) {
				if (other.parent != null)
					return false;
			} else if (!parent.equals(other.parent))
				return false;
			if (start != other.start)
				return false;
			if (visible != other.visible)
				return false;
			return true;
		}
		
		public boolean intersects(Segment s){
			return intersects(s.startPos(), s.endPos());
		}
		
		public Vector intersectsAt(Segment s){
			return intersectsAt(s.startPos(), s.endPos());
		}
		
		public float getSegmentPos(Vector at){
			float dx = endPos().x - startPos().x;
			float px = at.x - startPos().x;
			if(dx != 0 && px <= dx && px > 0) return px / dx;
			float dy = endPos().y - startPos().y;
			float py = at.y - startPos().y;
			if(dy != 0 && py <= dy && py > 0) return py / dy;
			float dz = endPos().z - startPos().z;
			float pz = at.z - startPos().z;
			if(dz != 0 && pz <= dz && pz > 0) return pz / dz;
			else return Float.NEGATIVE_INFINITY;
		}
		
		public void setIntersects(ArrayList<Segment> segments){
			Iterator<Segment> sit = segments.iterator();
			while(sit.hasNext()){
				Segment s = sit.next();
				if(s.intersects(this)){
					Vector at = s.intersectsAt(this);
					intersects.put(s, getSegmentPos(at));
				}
			}
		}
	}
